package fabricas;

import fantasma.Fantasmas;
import fantasma.tipos.FantasmaBuscador;
import fantasma.tipos.FantasmaBuscadorTemperamental;
import fantasma.tipos.FantasmaPerezoso;
import fantasma.tipos.FantasmaZonzo;
import interfaces.IControlador;
import interfaces.IDibujable;
import interfaces.IFantasma;
import interfaces.ILaberinto;
import interfaces.IPacman;
import interfaces.IVista;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import laberinto.Bolita;
import laberinto.Bolon;
import laberinto.Casilla;
import laberinto.Fruta;
import laberinto.Niveles;
import personajes.NullPacman;
import utilidades.Constantes;
import vista.SuperficieDeDibujo;
import vista.VisualizacionXMLDeEstadosDePersonajes;
import vista.VisualizacionXMLDeLaberinto;
import Controlador.ControladorDeMovimientoDePacmanPorTeclado;
import Controlador.ControladorXMLDelMovimientoDePacman;
import Controlador.MiVentana;
import app.Juego;


public class FabricaDeJuego {

	/* nuevo método para crear el juego*/
	public static Juego crearJuegoConVistaGraficaYControladoPorTeclado(String pathLaberinto) {
		
		MiVentana ventana = new MiVentana("ventana",Constantes.ANCHO_PANTALLA + Constantes.OFFSET_CASILLAS_X , Constantes.ALTO_PANTALLA + Constantes.OFFSET_CASILLAS_Y*3);
		SuperficieDeDibujo superficieDeDibujo = new SuperficieDeDibujo(Constantes.PATH_IMAGEN_DE_FONDO,Constantes.ANCHO_PANTALLA ,Constantes.ALTO_PANTALLA,Constantes.MODO_DEBUG);
		ventana.agregarComponente(superficieDeDibujo, 1, 1, 0, 0);
							
		Juego juego = new Juego(superficieDeDibujo,Constantes.CANTIDAD_DE_TICKS_DEL_ESCENARIO_NORMAL);
		
		/* agrego  niveles de la parte logica**************************************************/
		
		ILaberinto laberinto = FabricaDeLaberintoDesdeXML.crearLaberinto(pathLaberinto,0);

		Niveles<ILaberinto> nivelesDeLaParteLogica = fabricarNivelesDeLaParteLogica(
				laberinto);
		
        juego.agregarNivelesLogicos(nivelesDeLaParteLogica);
		
        /* agrego personajes ***********************************************************/
        
        IPacman pacman = FabricaPacman.crearPacmanEscenarioNormal(laberinto);
        juego.agregarPacman(pacman);
        
		Fantasmas fantasmas= crearFantamasmas(juego, laberinto);
		juego.agregarFantasmas(fantasmas);
		
        Fruta fruta = new Fruta( laberinto.obtenerCasillaInicialFantasmas());
        juego.agregarFruta(fruta);
		/**************************************************************************************/
		/* agrego 2 niveles para 2 dibujables (dibujable pacman y dibujable fantasmaZonzo)*/

		
        crearDIbujables(juego, laberinto, pacman);
		
        ventana.agregarControladorDeEventoDelTeclado(new ControladorDeMovimientoDePacmanPorTeclado(pacman));
        return juego;
	}
	public static Juego crearJuegoConVistaGraficaYControladoPorTeclado(String pathLaberinto, Juego juego, int nivel) {
		IPacman pacman = juego.obtenerPacman();
		
		MiVentana.ObtenerVentana().dispose();
		
		MiVentana ventana = new MiVentana("ventana",Constantes.ANCHO_PANTALLA + Constantes.OFFSET_CASILLAS_X , Constantes.ALTO_PANTALLA + Constantes.OFFSET_CASILLAS_Y*3);
		
		SuperficieDeDibujo superficieDeDibujo = new SuperficieDeDibujo(Constantes.PATH_IMAGEN_DE_FONDO,Constantes.ANCHO_PANTALLA ,Constantes.ALTO_PANTALLA,Constantes.MODO_DEBUG);
		ventana.agregarComponente(superficieDeDibujo, 1, 1, 0, 0);
							
		juego = new Juego(superficieDeDibujo,Constantes.CANTIDAD_DE_TICKS_DEL_ESCENARIO_NORMAL);
		
		/* agrego  niveles de la parte logica**************************************************/
		
		ILaberinto laberinto = FabricaDeLaberintoDesdeXML.crearLaberinto(pathLaberinto, nivel);
		
		Niveles<ILaberinto> nivelesDeLaParteLogica = fabricarNivelesDeLaParteLogica(laberinto);
		
        juego.agregarNivelesLogicos(nivelesDeLaParteLogica);
		
        /* agrego personajes ***********************************************************/
        pacman.cambiarLaberintoOriginalPor(laberinto);
        juego.agregarPacman(pacman);
        
		Fantasmas fantasmas= crearFantamasmas(juego, laberinto);
		juego.agregarFantasmas(fantasmas);
		
		Casilla casilla = fantasmas.obtenerArrayListDeFantasmas().get(0).obtenerCasilla();
        Fruta fruta = new Fruta(casilla);
        juego.agregarFruta(fruta);
		/**************************************************************************************/
		/* agrego 2 niveles para 2 dibujables (dibujable pacman y dibujable fantasmaZonzo)*/
		
        crearDIbujables(juego, laberinto, pacman);
		
        ventana.agregarControladorDeEventoDelTeclado(new ControladorDeMovimientoDePacmanPorTeclado(pacman));
        return juego;
	}

	private static void crearDIbujables(Juego juego,
			ILaberinto laberinto, IPacman pacman) {
		crearDibujableDelFondoDePantalla(juego);
        crearDibujableDelPacman(juego, laberinto, pacman);
        crearDibujablesDeFantasmas(juego, laberinto);
        crearDibujablesDeBolones(juego, laberinto);
        crearDibujablesDeBolitas(juego, laberinto);
        crearDibujableDeLaFruta(juego, laberinto);
	}

	private static void crearDibujableDelFondoDePantalla(Juego juego) {
		IDibujable fondoDibujable = FabricaDeGraficos.crearGraficoDelFondo();
        Niveles<IDibujable> nivelesDelFondoDibujable = fabricaDeNivelesDelDibujable(fondoDibujable);
        juego.agregarNivelesDelDibujable(nivelesDelFondoDibujable);
	}

	private static void crearDibujableDelPacman(Juego juego,
			ILaberinto laberintoNivel, IPacman pacman) {
		
		IDibujable pacmanDibujableNivel = FabricaDeGraficos.crearGraficosDelPacman(pacman,laberintoNivel);
		Niveles<IDibujable> nivelesDelPacmanDibujable = fabricaDeNivelesDelDibujable(pacmanDibujableNivel);
        juego.agregarNivelesDelDibujable(nivelesDelPacmanDibujable);
	}
	
	private static void crearDibujableDeLaFruta(Juego juego,
			ILaberinto laberinto) {
		
		IDibujable FrutaDibujable = FabricaDeGraficos.crearGraficosDeLaFruta(juego.obtenerFruta(),laberinto);
		Niveles<IDibujable> nivelesDeLaFrutaDibujable = fabricaDeNivelesDelDibujable(FrutaDibujable);
        juego.agregarNivelesDelDibujable(nivelesDeLaFrutaDibujable);
	}

	private static Fantasmas crearFantamasmas(Juego juego,
			ILaberinto laberintoNivel) {
		laberintoNivel.agregarFantasmas(new FantasmaBuscador("con ira"),1);
		laberintoNivel.agregarFantasmas(new FantasmaBuscadorTemperamental("con ira"),2);
		laberintoNivel.agregarFantasmas(new FantasmaZonzo("con ira"),-1);
		laberintoNivel.agregarFantasmas(new FantasmaPerezoso("con ira"),-2);
		for (Bolon bolon : laberintoNivel.ObtenerBolones()){
			for (IFantasma fantasma : laberintoNivel.obtenerFantasmas().obtenerArrayListDeFantasmas()){
				bolon.agregar(fantasma);
			}
		}
	
		return laberintoNivel.obtenerFantasmas();
	}

	private static void crearDibujablesDeFantasmas(Juego juego, ILaberinto laberintoNivel) {
		Fantasmas fantasmasNivel = laberintoNivel.obtenerFantasmas();
        ArrayList<IFantasma> coleccionFantasmas = fantasmasNivel.obtenerArrayListDeFantasmas();

        int indice=0;
        while(indice<coleccionFantasmas.size()){
        	IFantasma fantasmaNivel= coleccionFantasmas.get(indice);
			
            IDibujable	fantasmaDibujableNivel =	FabricaDeGraficos.crearGraficosDelFantasma(fantasmaNivel.obtenerColor(),fantasmaNivel,laberintoNivel);
			
			Niveles<IDibujable> nivelesDelFantasmaDibujable = fabricaDeNivelesDelDibujable(fantasmaDibujableNivel);        
	        
			juego.agregarNivelesDelDibujable(nivelesDelFantasmaDibujable);
            indice++;
        }
	}

	private static void crearDibujablesDeBolones(Juego juego, ILaberinto laberintoNivel){
		ArrayList<Bolon> bolones = laberintoNivel.ObtenerBolones();
		int indice=0;
		while(indice<bolones.size()){

			IDibujable bolonDibujableNivel = FabricaDeGraficos.crearGraficosDelBolon(bolones.get(indice),laberintoNivel);

			Niveles<IDibujable> nivelesDelBolonDibujable = fabricaDeNivelesDelDibujable(bolonDibujableNivel);        
	        
			juego.agregarNivelesDelDibujable(nivelesDelBolonDibujable);
			indice++;
		}		
		
	}
	
	private static void crearDibujablesDeBolitas(Juego juego, ILaberinto laberintoNivel){
		ArrayList<Bolita> bolitas = laberintoNivel.ObtenerBolitas();
		int indice=0;
		while(indice<bolitas.size()){

			IDibujable bolitaDibujableNivel = FabricaDeGraficos.crearGraficosDeLaBolita(laberintoNivel, bolitas.get(indice));

			Niveles<IDibujable> nivelesDelBolitaDibujable = fabricaDeNivelesDelDibujable(bolitaDibujableNivel);        
	        
			juego.agregarNivelesDelDibujable(nivelesDelBolitaDibujable);
			indice++;
		}
	}
	
	
	
	private static Niveles<ILaberinto> fabricarNivelesDeLaParteLogica(
			ILaberinto laberinto) {
		
		ArrayList<ILaberinto> coleccionNivelesDeLaParteLogica = new ArrayList<ILaberinto> ();
		
		coleccionNivelesDeLaParteLogica.add(laberinto);
        
		Niveles<ILaberinto> nivelesDeLaParteLogica = new Niveles<ILaberinto>(coleccionNivelesDeLaParteLogica);
		
        return nivelesDeLaParteLogica;
	}
	
	private static  Niveles<IDibujable> fabricaDeNivelesDelDibujable(IDibujable dibujableNivel){
		
		ArrayList<IDibujable> coleccionNivelesDelDibujable = new ArrayList<IDibujable> ();
		
		coleccionNivelesDelDibujable.add(dibujableNivel);
		
		Niveles<IDibujable> nivelesDelDibujable = new Niveles<IDibujable>(coleccionNivelesDelDibujable);
        
        return nivelesDelDibujable;
	}
	/* fin del nuevo método (y sus métodos auxiliares) para crear el juego*/
	
	

	/**
     * Juego con cuatro fantasmas, un pacman, un laberinto simple
     * Un controlador xml, dos vistas xml (uno para laberintos y uno para personajes)
     * @return
     */
	public static Juego crearJuegoEscenarioNormal(String pathLaberinto, String pathMovimientosDelPacman, String pathSalidaLaberinto, String pathSalidaPersonajes){		
		ILaberinto laberinto = FabricaDeLaberintoDesdeXML.crearLaberinto(pathLaberinto);	
		laberinto.agregarFantasmas(new FantasmaBuscador("con ira"));
		laberinto.agregarFantasmas(new FantasmaBuscadorTemperamental("con ira"));
		laberinto.agregarFantasmas(new FantasmaZonzo("con ira"));
		laberinto.agregarFantasmas(new FantasmaPerezoso("con ira"));

		return crearJuego(laberinto,laberinto.obtenerFantasmas(),pathLaberinto,pathMovimientosDelPacman,pathSalidaLaberinto,pathSalidaPersonajes,Constantes.CICLOS_PARA_MOVERSE+1);		
	}
	
	public static Juego crearJuegoEscenario1(String pathLaberinto, String pathMovimientosDelPacman, String pathSalidaLaberinto, String pathSalidaPersonajes){
		ILaberinto laberinto = FabricaDeLaberintoDesdeXML.crearLaberinto(pathLaberinto);		

		laberinto.agregarFantasmas(new FantasmaBuscador("escenario1"));
		
		return crearJuegoConFantasmaYSinPacman(pathSalidaLaberinto,
				pathSalidaPersonajes, laberinto, laberinto.obtenerFantasmas(), Constantes.CANTIDAD_DE_TICKS_DEL_ESCENARIO_1);
	}

	private static Juego crearJuegoConFantasmaYSinPacman(
			String pathSalidaLaberinto, String pathSalidaPersonajes,
			ILaberinto laberinto, Fantasmas fantasmas, int ticksTotales) {
		List<IControlador> controladores = new LinkedList<IControlador>();
		List<IVista> vistas = new LinkedList<IVista>();
		
		visualizacionXMLDelLaberinto(laberinto, vistas, pathSalidaLaberinto);				
		visualizacionXMLDelEstadoDePersonajes(new NullPacman(), fantasmas, vistas, pathSalidaPersonajes);
		
		return new Juego(fantasmas,controladores, vistas, ticksTotales);
	}
	
	public static Juego crearJuegoEscenario2(String pathLaberinto, String pathMovimientosDelPacman, String pathSalidaLaberinto, String pathSalidaPersonajes){
		ILaberinto laberinto = FabricaDeLaberintoDesdeXML.crearLaberinto(pathLaberinto);		

		IPacman pacman = FabricaPacman.crearPacmanEscenarioNormal(laberinto);

		
		return crearJuegoConPacmanYFantasmas(pathMovimientosDelPacman,
				pathSalidaLaberinto, pathSalidaPersonajes, laberinto,pacman, Constantes.CANTIDAD_DE_TICKS_DEL_ESCENARIO_2);
	}	

	public static Juego crearJuegoEscenario3(String pathLaberinto, String pathMovimientosDelPacman, String pathSalidaLaberinto, String pathSalidaPersonajes){
		ILaberinto laberinto = FabricaDeLaberintoDesdeXML.crearLaberinto(pathLaberinto);		

		laberinto.agregarFantasmas(new FantasmaBuscador("escenario 3"));

		IPacman pacman = FabricaPacman.crearPacmanEscenarioNormal(laberinto);

		
		return crearJuegoConPacmanYFantasmas(pathMovimientosDelPacman,
				pathSalidaLaberinto, pathSalidaPersonajes, laberinto,pacman, Constantes.CANTIDAD_DE_TICKS_DEL_ESCENARIO_3);
	}		
	
	

	public static Juego crearJuegoEscenario4(String pathLaberinto, String pathMovimientosDelPacman, String pathSalidaLaberinto, String pathSalidaPersonajes){
		ILaberinto laberinto = FabricaDeLaberintoDesdeXML.crearLaberinto(pathLaberinto);		
		
		laberinto.agregarFantasmas(new FantasmaBuscador("escenario 4"));

		IPacman pacman = FabricaPacman.crearPacmanEscenarioNormal(laberinto);

		for (Bolon bolon : laberinto.ObtenerBolones()){
			for (IFantasma fantasma : laberinto.obtenerFantasmas().obtenerArrayListDeFantasmas()){
				bolon.agregar(fantasma);
			}
		}

		return crearJuegoConPacmanYFantasmas(pathMovimientosDelPacman,
				pathSalidaLaberinto, pathSalidaPersonajes, laberinto,pacman, Constantes.CANTIDAD_DE_TICKS_DEL_ESCENARIO_4);
	}

	private static Juego crearJuegoConPacmanYFantasmas(
			String pathMovimientosDelPacman, String pathSalidaLaberinto,
			String pathSalidaPersonajes, ILaberinto laberinto, IPacman pacman, int ticksTotales) {
		List<IControlador> controladores = new LinkedList<IControlador>();
		List<IVista> vistas = new LinkedList<IVista>();
		
		construccionDelControladorXMLDelMovimientoDelPacman(pacman,controladores,pathMovimientosDelPacman);				

		visualizacionXMLDelLaberinto(laberinto, vistas, pathSalidaLaberinto);				
		visualizacionXMLDelEstadoDePersonajes(pacman, laberinto.obtenerFantasmas(), vistas, pathSalidaPersonajes);
		
		return new Juego(pacman,laberinto,controladores, vistas, ticksTotales);
	}	
	

	private static Juego crearJuego(ILaberinto laberinto,Fantasmas fantasmas,String pathLaberinto, String pathMovimientosDelPacman, String pathSalidaLaberinto, String pathSalidaPersonajes,int ciclos){		
		List<IControlador> controladores = new LinkedList<IControlador>();
		List<IVista> vistas = new LinkedList<IVista>();
				
		laberinto.cambiarFantasmas(fantasmas);
		IPacman pacman = FabricaPacman.crearPacmanEscenarioNormal(laberinto);
		
		construccionDelControladorXMLDelMovimientoDelPacman(pacman,controladores,pathMovimientosDelPacman);				
		visualizacionXMLDelLaberinto(laberinto, vistas, pathSalidaLaberinto);				
		visualizacionXMLDelEstadoDePersonajes(pacman, fantasmas, vistas, pathSalidaPersonajes);
		
		Juego juego = new Juego(ciclos);
		juego.agregarControladorXML(controladores.get(0));
		juego.agregarVistasXML(vistas);
		juego.agregarPacman(pacman);
		juego.agregarFantasmas(laberinto.obtenerFantasmas());
		return juego;//return new Juego(pacman,laberinto,controladores, vistas, ciclos);		
	}

	
	private static void construccionDelControladorXMLDelMovimientoDelPacman(IPacman pacman, List<IControlador> controladores,String rutaArchivo) {
		IControlador controladorXMLDelMovimientoDePacman = new ControladorXMLDelMovimientoDePacman(pacman,rutaArchivo);
		controladores.add(controladorXMLDelMovimientoDePacman);
	}
	
	private static void visualizacionXMLDelLaberinto(ILaberinto laberinto,List<IVista> vistas, String rutaArchivoLaberinto) {
		IVista visualizacionXMLDeLaberinto = new VisualizacionXMLDeLaberinto(laberinto, rutaArchivoLaberinto);
		vistas.add(visualizacionXMLDeLaberinto);
	}
	
	private static void visualizacionXMLDelEstadoDePersonajes(IPacman pacman,Fantasmas fantasmas, List<IVista> vistas,String rutaArchivoPersonajes) {
		IVista visualizacionXMLDeEstadosDePersonajes = new VisualizacionXMLDeEstadosDePersonajes(pacman,fantasmas,rutaArchivoPersonajes);
	    vistas.add(visualizacionXMLDeEstadosDePersonajes);
	}
}